﻿using System;
using Fine.Utils.Functions;

namespace Fine.Utils.Structs
{
    /// <summary>
    /// Interval of integers.
    /// Both borders are inclusive.
    /// </summary>
    public struct IntInterval
    {
        /// <summary>
        /// Beginning of the interval.
        /// </summary>
        public readonly int Beg;

        /// <summary>
        /// Ending of the interval.
        /// </summary>
        public readonly int End;


        /// <summary>
        /// Creates an interval.
        /// </summary>
        /// <param name="beg">beginning (the lower bound).</param>
        /// <param name="end">ending (the upper bound).</param>
        public IntInterval(int beg, int end)
        {
            if (beg > end)
                throw new ArgumentException("Invalid interval {0}..{1}.".With(beg,end));

            Beg = beg;
            End = end;
        }


        /// <summary>
        /// Count of integer values in the interval, including both borders.
        /// Calculates as (<c>End</c> - <c>Beg</c> + 1).
        /// </summary>
        public int Count
        {
            get { return End - Beg + 1; }
        }


        /// <summary>
        /// Checks that the given value contains in the interval.
        /// </summary>
        /// <param name="x">value to check.</param>
        /// <returns></returns>
        public bool Contains(int x)
        {
            return Beg <= x && x <= End;
        }


        /// <summary>
        /// Returns an array of X objects.
        /// </summary>
        /// <typeparam name="X">type of objects to return.</typeparam>
        /// <param name="converter">function that provides an X object for every integer from the interval.</param>
        /// <returns>array of X objects.</returns>
        public X[] ToArray<X>(Converter<int,X> converter)
        {
            X[] array = new X[Count];
            for (int i = 0, k = Beg; k <= End; i++, k++)
                array[i] = converter(k);
            return array;
        }

    }
}
